`timescale 1ns/1ps

   //============== (1) ==================
   //signals declaration
module test ;
    reg          clk;
    reg          rstn ;
    reg [1:0]    din ;
    reg          din_en ;
    wire [7:0]   dout ;
    wire         dout_en ;

    //============== (2) ==================

    // 定义时钟信号
    //clock generating
    real         CYCLE_200MHz = 5 ; //200MHz ，每个周期5纳秒
    always begin
        clk = 0 ; #(CYCLE_200MHz/2) ;
        clk = 1 ; #(CYCLE_200MHz/2) ;
    end

    //============== (3) ==================
    //reset generating
    // 定义复位信号，开始为0，8纳秒后为1
    initial begin
        rstn      = 1'b0 ;
        #8 rstn      = 1'b1 ;
    end

    //============== (4) ==================
    //motivation
    int          fd_rd ;            // 文件的句柄   
    reg [7:0]    data_in_temp ;     // for self check
    reg [15:0]   read_temp ;        // 8bit ascii data, 8bit 
    initial begin
        din_en    = 1'b0 ;          // 暂时取消输入
        din       = 'b0 ;           // 定义输入数据
        open_file("../tb/data_in.dat", "r", fd_rd); // fd_rd 为输入数据
        wait (rstn) ;               // 等待 rstn 启动
        # CYCLE_200MHz ;            // 等待 一个时钟周期

        //read data from file
        while (! $feof(fd_rd) ) begin   // $feof 是否读取到文件末尾
            @(negedge clk) ;            // 如果碰到时钟的向下延，那么就开始往下走。
            $fread(read_temp, fd_rd);   // $fread 读取16 bit，即 2byte
            din    = read_temp[9:8] ;   // 讲9~8 设置为输入
            data_in_temp = {data_in_temp[5:0], din} ; // data_in_temp 左移2位
            din_en = 1'b1 ;             // 输入有效位置 1
        end

        //stop data
        @(posedge clk) ;  //(4.5)       // 等待时钟向上延
        #2 din_en = 1'b0 ;              // 延迟2纳秒之后  输入有效位置 0 （停止拼接）
    end

    //open task
    // 定义打开文件的task，有点类似方法
    task open_file;
        input string      file_dir_name ;
        input string      rw ;
        output int        fd ;

        fd = $fopen(file_dir_name, rw);
        if (! fd) begin
            $display("--- iii --- Failed to open file: %s", file_dir_name);
        end
        else begin
            $display("--- iii --- %s has been opened successfully.", file_dir_name);
        end
    endtask

    //============== (5) ==================
    // 定义拼接模块
    data_consolidation    u_data_process
    (
      .clk              (clk),
      .rstn             (rstn),
      .din              (din),
      .din_en           (din_en),
      .dout             (dout),
      .dout_en          (dout_en)
     );

    //============== (6) ==================
    //auto check
    reg  [7:0]           err_cnt ;
    int                  fd_wr ;

    initial begin
        err_cnt   = 'b0 ;

        // 打开输出文件
        open_file("../tb/data_out.dat", "w", fd_wr);
        forever begin
            @(negedge clk) ;
            if (dout_en) begin
                $fdisplay(fd_wr, "%h", dout);
            end
        end
    end

    always @(posedge clk) begin

        // 延迟1ns
        #1 ;

        // 如果有效输出
        if (dout_en) begin
            if (data_in_temp != dout) begin
                err_cnt = err_cnt + 1'b1 ;
            end
        end
    end

    //============== (7) ==================
    //simulation finish
    always begin
        #100;
        if ($time >= 10000)  begin
            if (!err_cnt) begin
                $display("-------------------------------------");
                $display("Data process is OK!!!");
                $display("-------------------------------------");
            end
            else begin
                $display("-------------------------------------");
                $display("Error occurs in data process!!!");
                $display("-------------------------------------");
            end
            #1 ;
            $finish ;
        end
    end

endmodule // test